package com.finance.cooperate.strategy.core.strategy;

import com.finance.cooperate.common.utils.AopTargetUtils;
import com.finance.cooperate.common.utils.DateUtils;
import com.finance.cooperate.common.utils.ProbabilityUtils;
import com.finance.cooperate.common.utils.StringUtil;
import com.finance.cooperate.dao.entity.secondary.StrategyInfo;
import com.finance.cooperate.dao.entity.secondary.StrategyRecord;
import com.finance.cooperate.dao.repository.secondary.StrategyRecordRepository;
import com.finance.cooperate.strategy.common.dto.StrategyInfoAndWeightDTO;
import com.finance.cooperate.strategy.core.common.Builder;
import com.finance.cooperate.strategy.core.common.Relationship;
import com.finance.cooperate.strategy.service.StrategyInfoService;
import io.vavr.Tuple2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * @ClassName StrategyBuilder
 * @Description 策略执行构建
 * @Author shenanxin
 * @Date 2023/8/23 15:47
 * @Modify ...
 */
@Component
@Slf4j
@SuppressWarnings("all")
public class StrategyBuilder extends Builder<StrategyHandler> {

    // 给个种子
    private final static Long BASE_SEED = 16L;

    @Resource
    private StrategyScope strategyScope;

    @Resource
    private StrategyRecordRepository strategyRecordRepository;

    @Autowired
    private StrategyInfoService strategyInfoService;

    @Override
    public void builder() {

        // 是否有策略
        boolean haveStrategy = false;

        try {
            // 多组关系遍历：and, or, group
            for (Tuple2<Relationship, List<StrategyHandler>> tuple: super.processors.get()) {

                int hitCount = 0;
                double finalScore = strategyScope.getFinalScore();

                if (tuple._1 == Relationship.group) {

                    String group = null;


                    // 要拿到该组所有的策略权重才能判断
                    for (StrategyHandler handler: tuple._2) {
                        // 1. 初始化资源
                        handler.init();

                        // 2. 判断策略是否需要执行
                        boolean flag = handler.isExecute();

                        // 3. 如果策略可用，获取Group
                        if (flag) {
                            Strategy strategy = strategyScope.getResult(AopTargetUtils.getTarget(handler).getClass());
                            group = strategy.getGroup();

                            if (!StringUtil.isEmptyOrNvl(group)) {
                                break;
                            }
                        }

                        // 4. 清理资源
                        handler.destroy();
                    }

                    // 所有策略遍历后还是拿不到可用 group 就不用执行了
                    if (!StringUtil.isEmptyOrNvl(group)) {

                        StrategyInfoAndWeightDTO dto = strategyInfoService.findAllStrategyInfoAndWeightByGroup(group);


                        List<StrategyInfo> strategyInfos = dto.getStrategyInfos();

                        // 获取执行策略

                        int index = ProbabilityUtils.shuntSelection(dto.getWeightList(), BASE_SEED * strategyScope.getUid().hashCode());

                        StrategyInfo strategyInfo = strategyInfos.get(index);

                        // 开始策略执行
                        for (StrategyHandler handler: tuple._2) {

                            // 1. 初始化资源
                            handler.init();

                            Strategy strategy = strategyScope.getResult(AopTargetUtils.getTarget(handler).getClass());

                            if (strategy.getName().equals(strategyInfo.getName())) {

                                // 找到策略
                                // 2. 判断该规则是否需要执行
                                boolean flag = handler.isExecute();

                                if (flag) {

                                    haveStrategy = true;

                                    // 3. 执行策略
                                    Long strategyId = handler.executeControl();

                                    // 4. 保存策略命中结果
                                    handler.save(strategyId);


                                    // 5. 判断是否命中
                                    if (strategy.isHit()) {

                                        hitCount ++;

                                        finalScore = strategy.getFinalScore();


                                        // 如果命中，判断是否继续执行，如果需要继续则继续，如果不需要，返回
                                        // 是否有必要执行
                                        if (!strategy.isContinueExecute()) {
                                            break;
                                        }

                                    }

                                }
                            }

                            // 6. 清理资源
                            handler.destroy();
                        }
                    }

                } else {

                    for (StrategyHandler handler: tuple._2) {

                        // 1. 初始化资源
                        handler.init();

                        // 2. 判断该策略是否需要执行
                        boolean flag = handler.isExecute();

                        if (flag) {

                            haveStrategy = true;

                            // 3. 执行策略
                            Long strategyId = handler.executeControl();


                            // 4. 保存策略命中结果
                            handler.save(strategyId);


                            // 5. 判断是否命中
                            Strategy strategy = strategyScope.getResult(AopTargetUtils.getTarget(handler).getClass());
                            if (strategy.isHit()) {
                                hitCount ++;
                                finalScore = strategy.getFinalScore();

                                if (tuple._1 != Relationship.and) {
                                    if (!strategy.isContinueExecute()) {
                                        break;
                                    }
                                }

                            }

                        }

                        // 6. 清理资源
                        handler.destroy();

                    }

                }



                // 6. 不同策略关系的不同处理方式【这里才能判断是否有策略命中，同一组】
                if (tuple._1 == Relationship.and) {
                    if (hitCount == tuple._2.size()) {
                        strategyScope.setHit(true);
                        // 命中要改变分数
                        strategyScope.setFinalScore(finalScore);
                    }
                } else if (tuple._1 == Relationship.or || tuple._1 == Relationship.group) {

                    if (hitCount > 0) {

                        strategyScope.setHit(true);
                        // 命中要改变分数
                        strategyScope.setFinalScore(finalScore);

                    }

                }

            }


            // 7. 对结果进行保存，前提是有策略执行【不是命中】
            if (haveStrategy) {
                StrategyRecord record = new StrategyRecord();
                record.setId(strategyScope.getRecodeId());
                record.setIsHit(strategyScope.isHit());
                record.setUid(strategyScope.getUid());
                record.setApplyId(strategyScope.getApplyId());
                record.setLoanNum(strategyScope.getLoanNum());
                record.setInitialScore(strategyScope.getInitialScore());
                record.setFinalScore(strategyScope.getFinalScore());
                record.setCreated(DateUtils.getMillis());
                strategyRecordRepository.save(record);
            }

        } catch (Exception e) {

            log.error(e.getMessage(), e);
        }


    }
}
